using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using RFS.BizLogic;
using RFS.BizLogic.PaiShi;
using RFS.BizLogic.PaiShi.Accounting;
using RFS.BizLogic.PaiShi.Impl;
using RFS.BizLogic.PaiShi.Ports;
using RFS.BizLogic.Sys;
using RFS.Domain.PaiShi;
using RFS.Domain.PaiShi.Accounting;
using RFS.Domain.PaiShi.WorkFlow;
using ycx;

namespace TestWPF2.PaiShi
{
    public class TAccounting
    {
        private IAntiObject _en;


        [SetUp]
        public void setup()
        {
            _en = Starter.StartApp(true);
        }


        [Test]
        public void T10_CreateAV_Given_Orders_ReturnAAv()
        {
            #region mock order

            var prod = new Product("s1", "p1", "10");


            var gho = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b1"
            };

            var yso = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b2"
            };

            #endregion

            #region mock price

            //mock the price
            var mprice = new Mock<IPriceManagerPort>();
            mprice.Setup(x => x.GetPrice(It.IsAny<DateTime>(), It.IsAny<IProduct>(),
                     
                    It.IsAny<bool>()
                ))
                .Returns(new ProductPriceItem() { Price = (decimal)1.1 });

            _en.RegisterMock4Test(mprice.Object);

            #endregion

            var ps = _en.Get<IAccountingVoucherManager>();
            var avs = ps.CreateAVs() ;
            var av = avs.CreateAV(gho,  yso );
            // av.Echo();
            
            av. Echo(asjson: false);

            Assert.AreEqual(1, av.CreditTotal.Quantity);
            Assert.AreEqual(2, av.CreditTotal.AmountCash);
            Assert.IsTrue(av.IsBalanced);
        }


        [Test]
        public void T10_CreateAVs_Given_2DataNode_ReturnNBalancedAvSet()
        {
            #region mock order

            var prod = new Product("s1", "p1", "10");


            var gho = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b1"
            };

            var yso = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b1"
            };

            #endregion

            #region mock price

            //mock the price
            var mprice = new Mock<IPriceManagerPort>();
            mprice.Setup(x => x.GetPrice(It.IsAny<DateTime>(), It.IsAny<IProduct>(),
                     
                    It.IsAny<bool>()
                ))
                .Returns(new ProductPriceItem() { Price = (decimal)1.1 });

            _en.RegisterMock4Test(mprice.Object);

            #endregion


            var leftNode = new WorkFlowNodeWrapper(new List<IOrderItem>()
            {
                gho
            }, DateTime.Today, "left node");

            var rNode = new WorkFlowNodeWrapper(new List<IOrderItem>()
            {
                yso
            }, DateTime.Today, nodeName: "right node");


            var ps = _en.Get<IAccountingVoucherManager>();
            var avs = ps.CreateAVs();
            avs.State.ToString().Echo();
            avs.KeyNote.Echo();
            // Assert.IsTrue(avs.State == VoucherState.自平);
            Assert.IsTrue(avs.Vouchers.Count() == 0);
            
            
        }


        //c1 改小数量, 自动核销失败，返回失败集 
        [Test]
        public void T10_CreateAVs_Given_2DeferentDataNode_ReturnNotBalancedAvSetWithProblems()
        {
            #region mock order

            var prod = new Product("s1", "p1", "10");

            var gho = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b1"
            };

            var yso = new OrderItem()
            {
                Product = prod,
                Quantity = 0,
                Amount = 0,
                BizId = "b1"
            };

            #endregion

            #region mock price

            //mock the price
            var mprice = new Mock<IPriceManagerPort>();
            mprice.Setup(x => x.GetPrice(It.IsAny<DateTime>(), It.IsAny<IProduct>(),
                     
                    It.IsAny<bool>()
                ))
                .Returns(new ProductPriceItem() { Price = (decimal)1.1 });
            _en.RegisterMock4Test(mprice.Object);

            #endregion

            #region node prepare

            var leftNode = new WorkFlowNodeWrapper(new List<IOrderItem>()
            {
                gho
            }, DateTime.Today, "left node");

            var rNode = new WorkFlowNodeWrapper(new List<IOrderItem>()
            {
                yso
            }, DateTime.Today, nodeName: "right node");
            

            #endregion

            var ps = _en.Get<IAccountingVoucherManager>();
            var avs2 = ps.CreateAVs( );
            var avs=avs2.CreateAV(gho,  yso );

            //detect problems
            // Assert.IsTrue(avs.State == VoucherState.待平);
            Assert.IsTrue(avs.Problem.IsAny);
            // Assert.IsTrue(avs.Vouchers.Count()==0); // no voucher is created 
            
            Console.WriteLine(avs.Problem.Message);
            
        }
        
                 
        [Test]
        public async Task T10_AVsStateTest_Given__ReturnNotBalanced()
        {
    
            var ps = _en.Get<IAccountingVoucherManager>();
            var avs = ps.CreateAVs( );
      
            avs.StateChanged+= (sender, args) => args.Echo();
            
            Assert.IsTrue(avs.State == VoucherSetState.准备);

            avs.GotoDefferenceProcess();
            Assert.IsTrue(avs.State == VoucherSetState.差异处理);

           Assert.ThrowsAsync< Exception>(async   ()=>await avs.LoadLeftNodeDataAsync() ) ;
           Assert.ThrowsAsync< Exception>(async   ()=>await avs.LoadRightNodeDataAsync() ) ;
            
           avs.GotoPreparingData();
           Assert.IsTrue(avs.State == VoucherSetState.准备);

           avs.CheckToCreateAVs();
           

        }
        
        
        

        //c1 差异处理：
        // 把所有不余留放入新凭证中
            // 显示在右边列表中
        // 保存，准备复制
        [Test]
        public void T10_GotoDefferenceProcess_ReProcessDefferences_ANewAVSshouldbeCreated()
        {
            #region mock order

            var prod = new Product("s1", "p1", "10");

            var gho = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b1"
            };

            var yso = new OrderItem()
            {
                Product = prod,
                Quantity = 0,
                Amount = 0,
                BizId = "b1"
            };

            #endregion

            #region mock price

            //mock the price
            var mprice = new Mock<IPriceManagerPort>();
            mprice.Setup(x => x.GetPrice(It.IsAny<DateTime>(), It.IsAny<IProduct>(),
                     
                    It.IsAny<bool>()
                ))
                .Returns(new ProductPriceItem() { Price = (decimal)1.1 });
            _en.RegisterMock4Test(mprice.Object);

            #endregion

            #region node prepare

            var leftNode = new WorkFlowNodeWrapper(new List<IOrderItem>()
            {
                gho
            }, DateTime.Today, "left node");

            var rNode = new WorkFlowNodeWrapper(new List<IOrderItem>()
            {
                yso
            }, DateTime.Today, nodeName: "right node");
            

            #endregion

            var ps = _en.Get<IAccountingVoucherManager>();
            var avs = ps.CreateAVs( );
            avs.LeftNode = leftNode;
            avs.RightNode = rNode;
            avs.CheckToCreateAVs();

            var ct = 0;

            Assert.IsTrue(avs.Vouchers.Count()==0); // no sys av is created
            
            avs.Changed += (sender, args) => ct++;
            avs.GotoDefferenceProcess();
            Thread.Sleep(1010); // wait for the event 
            ct.Echo();
            // avs.ManualVouchers.Echo(); // a balancing av should be create base on Nodes data
            var avd= avs.ManualVouchers.ElementAt(0) ; // a balancing av should be create base on Nodes data
            Assert.IsTrue(avd.VType == VType.差异处理 );
            Assert.IsTrue(avd.Balance.AmountCash==-2 );
            Assert.IsTrue(ct==1);
            
        }


         [Test]
        public void T10_RemoveAV_ANewAVSshouldbeCreated()
        {
            #region mock order

            var prod = new Product("s1", "p1", "10");

            var gho = new OrderItem()
            {
                Product = prod,
                Quantity = 1,
                Amount = 2,
                BizId = "b1"
            };

            var yso = new OrderItem()
            {
                Product = prod,
                Quantity = 0,
                Amount = 0,
                BizId = "b1"
            };

            #endregion

            
            var ps = _en.Get<IAccountingVoucherManager>();
            var avs = ps.CreateAVs( );
            var av=avs.CreateAV(gho, yso);
            Assert.AreEqual(avs.Vouchers.Count(),1);
            int ct = 0;

            avs.Changed += (sender, args) => ct++; 
            avs.RemoveAV(av);
            
            Thread.Sleep(1010);
            Assert.AreEqual(avs.Vouchers.Count(),0); 
            Assert.AreEqual(ct,1); 


        }


        
 
    }
}